﻿using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp.Demos.Coroutine
{

    class CoroutineContainerBase : ICoroutineContainer
    {
        /// <summary>
        /// 提交到待运行列表中的协程单元
        /// </summary>
        private List<CoroutineItem> penddingUnits = new List<CoroutineItem>();

        /// <summary>
        /// 已注册，单未提交到待运行列表中的协程单元
        /// </summary>
        private List<CoroutineItem> registedUnits = new List<CoroutineItem>();

        /// <summary>
        /// 错误处理
        /// </summary>
        private Action<ICoroutineTask, Exception> _errorHandler;

        public CoroutineContainerBase(Action<ICoroutineTask, Exception> errorHandler)
        {
            _errorHandler = errorHandler;
        }

        public void Register(ICoroutineTask unit)
        {
            lock (registedUnits)
            {
                registedUnits.Add(new CoroutineItem { CoroutineTask = unit, CoroutineResult = null });
            }
        }

        public void Run()
        {
            // 开启一个单独任务执行
            Task.Run(() =>
            {
                while (true)
                {
                    // 这个 While 一直在输出
                    Thread.Sleep(100);
                    //Console.WriteLine("While...");

                    // 加入到待运行列表中
                    lock (registedUnits)
                    {
                        foreach (var tp in registedUnits)
                        {
                            penddingUnits.Add(tp);
                        }
                        // 添加完成后，清空列表
                        registedUnits.Clear();
                    }

                    // 记录处理失败的协程单元
                    CoroutineItem errorUnitItem = null;

                    // 已完成的协程单元
                    CoroutineItem completedUnitItem = null;

                    // 依次处理协程单元
                    foreach (CoroutineItem unitItem in penddingUnits)
                    {
                        // 每次开始时，重置为 null
                        errorUnitItem = null;

                        // 协程单元还没有开始
                        if (unitItem.CoroutineResult == null)
                        {
                            // 获取要处理的"任务迭代器"
                            IEnumerator<Task> result = unitItem.CoroutineTask.GetTasks();

                            Console.WriteLine("GetTask Complete");

                            try
                            {
                                Console.WriteLine($"Begin MoveNext");
                                // 调用 MoveNext() 方法的时候
                                // 就开始执行 Task 了
                                result.MoveNext();
                            }
                            catch (Exception ex)
                            {
                                // 出现了异常，调用对应的异常处理器
                                _errorHandler(unitItem.CoroutineTask, ex);

                                // 将失败的协程单元记录下来
                                errorUnitItem = unitItem;

                                break;
                            }

                            // 将处理结果保存起来
                            // 此时
                            // tp.UnitResult != null
                            unitItem.CoroutineResult = result;
                        }
                        else
                        {
                            // tp.UnitResult != null
                            // 表示执行了 MoveNext

                            // 已完成（取消 or 完成 or 失败）
                            if (unitItem.CoroutineResult.Current.IsCanceled || unitItem.CoroutineResult.Current.IsCompleted || unitItem.CoroutineResult.Current.IsFaulted)
                            {
                                // 表示是否还有下一个任务
                                bool nextTask = true;

                                // DEBUG 
                                // 如果是 WebClient 任务，输出对应的响应信息
                                if (unitItem.CoroutineResult.Current is Task<HttpResponseMessage>)
                                {
                                    var resposne = unitItem.CoroutineResult.Current as Task<HttpResponseMessage>;
                                    var content = resposne.Result.Content.ReadAsByteArrayAsync().Result;
                                    Console.WriteLine($"    Url:{resposne.Result.RequestMessage.RequestUri}: Size:{content.Length}");
                                }
                                else
                                {
                                    Console.WriteLine($"    Do Delay");
                                }

                                try
                                {
                                    Console.WriteLine($"Continue MoveNext");
                                    // 继续获取迭代器中的内容（执行下一个 Task）
                                    nextTask = unitItem.CoroutineResult.MoveNext();
                                }
                                catch (Exception ex)
                                {
                                    _errorHandler(unitItem.CoroutineTask, ex);

                                    // 将失败的协程单元记录下来
                                    errorUnitItem = unitItem;
                                    break;
                                }

                                // 迭代器中没有更多的元素了
                                // 将其移除
                                if (!nextTask)
                                {
                                    completedUnitItem = unitItem;
                                    // 跳出 for-each
                                    break;
                                }
                            }
                        }
                    }  // for-each end

                    // 由于 while true 每次都从集合中迭代
                    // 此次，将已完成的对象，移除掉
                    // 全部处理完成后
                    // penddingUnits 集合应该为空
                    // 可以跳出 while true 循环
                    if (errorUnitItem != null)
                    {
                        penddingUnits.Remove(errorUnitItem);
                    }

                    if (completedUnitItem != null)
                    {
                        penddingUnits.Remove(completedUnitItem);
                    }


                    if (penddingUnits.Count == 0)
                    {
                        lock (registedUnits)
                        {
                            if (registedUnits.Count == 0)
                            {
                                // 没有更多项目了
                                // 跳出 while (true) 
                                break;
                            }
                        }
                    }
                }
                Console.WriteLine();
                Console.WriteLine("--- Coroutine Complete ---");
            });
        }
    }
}
